using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace umlungu.engineX.pop3X {
	/// <summary>
	/// umlungu engineX blog Pop3 class.
	/// </summary>
	public class x_pop3msg
	{
		/// <summary>
		/// Local objects and properties
		/// </summary>
		private x_pop3body _messageComponents;
		private string _contentType;
		private string _multipartBoundary;
		public IEnumerator MultipartEnumerator {	get { return _messageComponents.ComponentEnumerator; }}
		
		private enum _linetype {
			From,
			To,
			Subject,
			ContentType,
			NotKnown = -99,
			EndOfHeader = -98
		}
		
		// From accessor
		private string _from;
		public string From {	get { return _from; }}
		// To accessor
		private string _to;
		public string To {	get { return _to; }}
		// Subject accessor
		private string _subject;
		public string Subject {	get { return _subject; }}
		// Body accessor
		private string _body;
		public string Body {	get { return _body; }}
		// IsMultipart accessor
		private bool _isMultipart = false;
		public bool IsMultipart {	get { return _isMultipart; }}

		private void ParseEmail(string[] lines) {
			long startOfBody = ParseHeader(lines);
			long numberOfLines = lines.Length;
			_messageComponents = new x_pop3body(lines, startOfBody, _multipartBoundary, _contentType);
		}
		private long ParseHeader(string[] lines) {
			int numberOfLines = lines.Length;
			long bodyStart = 0;

			for(int i=0; i<numberOfLines; i++) {
				string currentLine = lines[i].Replace("\n","");
				_linetype lineType = GetHeader_linetype(currentLine);
				switch(lineType) {
					// From:
					case _linetype.From:
						_from = x_pop3parse.From(currentLine);	
						break;
					// Subject:
					case _linetype.Subject:
						_subject = x_pop3parse.Subject(currentLine);
						break;
					// To:
					case _linetype.To:
						_to = x_pop3parse.To(currentLine);
						break;
					// Content-Type
					case _linetype.ContentType:
						_contentType = x_pop3parse.ContentType(currentLine);
						_isMultipart = x_pop3parse.IsMultipart(_contentType);
						if(_isMultipart) {
							// if boundary definition is on next line ...
							if(_contentType.Substring(_contentType.Length-1,1).Equals(";")) {
								++i;
								_multipartBoundary = x_pop3parse.MultipartBoundary(lines[i].Replace("\n",""));
							} else { // boundary definition is on same line as "Content-Type" ...
								_multipartBoundary = x_pop3parse.MultipartBoundary(_contentType);
							}
						}
						break;
					case _linetype.EndOfHeader:
						bodyStart = i+1;
						break;
				}
				if(bodyStart>0)
					break;
			}
			return(bodyStart);
		}
		private _linetype GetHeader_linetype(string line) {
			_linetype type = _linetype.NotKnown;
			if( Regex.Match(line,"^From:"+".*$").Success ) {
				type = _linetype.From;
			} else if( Regex.Match(line,"^To:"+".*$").Success ) {
				type = _linetype.To;
			} else if( Regex.Match(line,"^Subject:"+".*$").Success ) {
				type = _linetype.Subject;
			} else if( Regex.Match(line,"^Content-Type:"+".*$").Success ) {
				type = _linetype.ContentType;
			} else if( line.Length == 0 ) {
				type = _linetype.EndOfHeader;
			}
			return type;
		}
		public x_pop3msg(string message) {
			ParseEmail(message.Split(new char[] { '\r'}));
			
			// get body (if it exists) ...
			IEnumerator multipartEnumerator = MultipartEnumerator;
			while( multipartEnumerator.MoveNext() ) {
				x_pop3att multipart = (x_pop3att) multipartEnumerator.Current;
				if( multipart.IsBody ) {
					_body = multipart.Data;
					break;
				}
			}
		}
		public override string ToString() {
			IEnumerator enumerator = MultipartEnumerator;
			string ret = 
				"From    : "+_from+ "\r\n"+
				"To      : "+_to+ "\r\n"+
				"Subject : "+_subject+"\r\n";

			while( enumerator.MoveNext() ) {
				ret += ((x_pop3att)enumerator.Current).ToString()+"\r\n";
			}
			return ret;
		}
	}
}
